package com.lhz.project.system.service.auth.impl;


import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lhz.common.constant.*;
import com.lhz.common.page.BaseQueryParam;
import com.lhz.common.page.NewPageBean;
import com.lhz.framework.security.HolderInfoManager;
import com.lhz.framework.security.token.UserTokenInfo;
import com.lhz.project.system.mapper.auth.MenuMapper;
import com.lhz.project.system.mapper.auth.RoleMenuMapper;
import com.lhz.project.system.model.entity.auth.Menu;
import com.lhz.project.system.model.entity.auth.RoleMenu;
import com.lhz.project.system.model.param.auth.MenuParam;
import com.lhz.project.system.model.vo.auth.MenuTreeVo;
import com.lhz.project.system.service.auth.MenuService;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author LiHuaZhi
 * @since 2020-06-15 22:42:37
 */
@Service

public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Resource
    private MenuMapper menuMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Override
    public Menu selectByPrimaryKey(Integer id) {
        return menuMapper.selectByPrimaryKey(id);
    }

    @Override
    public Object listMenu(BaseQueryParam param) {
        //获取人员信息
        UserTokenInfo user = HolderInfoManager.getUserInfo().getUser();
        String userId = null;
        //非系统管理员更具优化id匹配菜单
        if (!user.getType().equals(AccountTypeConstant.ADMIN)) {
            userId = user.getId();
        }
        String finalUserId = userId;
        return NewPageBean.generatePage(() -> menuMapper.listMenu(param, finalUserId), param, Menu.class);
    }

    @Override
    public int insert(MenuParam param) {
        //判断名称不重复
        checkName(param.getName(), param.getId());
        //校验外链地址
        if (param.getIsFrame().equals(DataStatusConstants.YES_FRAME)) {
            checkFrameAddr(param.getPath());
        }
        String userId = HolderInfoManager.getUserId();
        Menu menu = new Menu();
        BeanUtils.copyProperties(param, menu);

        menu.setStatus(DataStatusEnum.VALID.getCode());
        menu.setCreateBy(userId);
        menu.setUpdateBy(userId);
        return menuMapper.insert(menu);
    }

    @Override
    public int updateByPrimaryKey(MenuParam param) {
        //判断名称不重复
        checkName(param.getName(), param.getId());

        //校验外链地址
        if (param.getIsFrame().equals(DataStatusConstants.YES_FRAME)) {
            checkFrameAddr(param.getPath());
        }
        //校验外链地址
        String userId = HolderInfoManager.getUserId();
        Menu menu = new Menu();
        BeanUtils.copyProperties(param, menu);

        menu.setUpdateBy(userId);
        return menuMapper.updateById(menu);
    }

    @Override
    public void deleteRealByPrimaryKey(Integer id) {
        //存在子菜单,不允许删除
        hasChildByParentId(id);
        //菜单已分配,不允许删除
        hasMenuExist(id);
        menuMapper.deleteById(id);
    }

    /**
     * 树形结构
     *
     * @return
     */
    @Override
    public List<MenuTreeVo> selectTreeMenu() {
        //查询列表
        //获取人员信息
        UserTokenInfo user = HolderInfoManager.getUserInfo().getUser();
        String userId = null;
        //非系统管理员更具优化id匹配菜单
        if (!user.getType().equals(AccountTypeConstant.ADMIN)) {
            userId = user.getId();
        }
        List<MenuTreeVo> list = menuMapper.selectTreeMenu(userId);
        return buildMenuTree(list);
    }

    //判断是否存在子节点
    private void hasChildByParentId(Integer id) {
        List<Menu> menus = menuMapper.selectByParentId(id);
        Assert.isTrue(menus.isEmpty(), ResponseState.HAS_CHILD_MENU.name());
    }

    //判断菜单是否已分配
    private void hasMenuExist(Integer id) {
        RoleMenu roleMenu = roleMenuMapper.selectByMenuId(id);
        Assert.isTrue(roleMenu == null, ResponseState.MENU_EXIST.name());
    }

    //检查名称是否重复
    private void checkName(String name, Integer id) {
        int size = menuMapper.checkName(name, id);
        Assert.isFalse(size > 0, ResponseState.REPEAT_ADD.name());
    }

    //检查外链地址格式
    private void checkFrameAddr(String path) {
        Assert.isFalse(!path.startsWith(SysConstants.HTTP) || !path.startsWith(SysConstants.HTTPS),
                "地址必须以http(s)://开头");
    }

    /**
     * 构建前端所需要树结构
     *
     * @param menuList 部门列表
     * @return 树结构列表
     */
    private List<MenuTreeVo> buildMenuTree(List<MenuTreeVo> menuList) {
        //新集合
        List<MenuTreeVo> returnList = new ArrayList<>();

        List<Integer> tempList = new ArrayList<>();
        for (MenuTreeVo menu : menuList) {
            tempList.add(menu.getId());
        }
        for (MenuTreeVo dept : menuList) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(menuList, dept);
                returnList.add(dept);
            }
        }
        //没有查询到节点则以当前节点
        if (returnList.isEmpty()) {
            returnList = menuList;
        }
        return returnList;
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<MenuTreeVo> list, MenuTreeVo t) {
        // 得到子节点列表
        List<MenuTreeVo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (MenuTreeVo tChild : childList) {
            // 判断是否有子节点
            if (Objects.isNull(tChild.getParentId()) && tChild.getParentId().equals(t.getId())) {
                for (MenuTreeVo n : childList) {
                    recursionFn(list, n);
                }
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<MenuTreeVo> getChildList(List<MenuTreeVo> list, MenuTreeVo t) {
        List<MenuTreeVo> tList = new ArrayList<>();
        for (MenuTreeVo n : list) {
            if (Objects.nonNull(n.getParentId()) && n.getParentId().equals(t.getId())) {
                tList.add(n);
            }
        }
        return tList;
    }
}